package serverMgr

import (
	"encoding/json"
	"src/zeus/common"
	"src/zeus/etcd"
	"src/zeus/iserver"
	"src/zeus/logger"
	"sync"

	"go.etcd.io/etcd/api/v3/mvccpb"
	clientv3 "go.etcd.io/etcd/client/v3"
)

type UserNumMapByLobby struct {
	lock *sync.RWMutex
	//服务器信息
	userNumMap map[uint32]map[uint64]*UserNumValue // key=groupid, value=map[serverId] usernum
}

func NewUserNumMapByLobby() (result *UserNumMapByLobby) {
	result = new(UserNumMapByLobby)
	var _ IServerMap = result
	result.lock = new(sync.RWMutex)
	result.userNumMap = map[uint32]map[uint64]*UserNumValue{}
	return
}

// Put 新增或更新服务器信息
func (this *UserNumMapByLobby) Put(sinfo *iserver.ServerInfo) {
}

// UpLoad 上传服务器信息
func (this *UserNumMapByLobby) UpLoad(path string, val int64) *iserver.ServerInfo {
	logger.Error("UpLoad not implement")
	return nil
}

// GetBalancing 负载均衡
func (this *UserNumMapByLobby) GetBalancing(groupid uint32, stype uint8) (result *iserver.ServerInfo, err error) {
	logger.Error("GetBalancing not implement")
	return nil, nil
}

// GetServerList 获取服务器列表
func (this *UserNumMapByLobby) GetServerList(sGroup uint32, sType uint8) ([]iserver.ServerInfo, error) {
	logger.Error("GetServerList not implement")
	return nil, nil
}

// GetServerByID 根据服务器ID获取服务器信息
func (this *UserNumMapByLobby) GetServerByID(groupid uint32, stype uint8, serverId uint64) (result *iserver.ServerInfo, err error) {
	logger.Error("GetServerByID not implement")
	return nil, nil
}

// Delete 删除服务器信息
func (this *UserNumMapByLobby) Delete(path string) {
	this.lock.Lock()
	defer this.lock.Unlock()
	groupid, _, sid := SplitLobbyUserKeyParam(string(path))
	_ = PATH_UserNum

	//有人数信息删除,group为空时不处理
	delete(this.userNumMap[groupid], sid)
}

// DeleteAll 删除所有服务器信息
func (this *UserNumMapByLobby) DeleteAll() {
	this.lock.RLock()
	defer this.lock.RUnlock()
	this.userNumMap = map[uint32]map[uint64]*UserNumValue{}
}

// WatchCallDelay 监听调用延迟
func (this *UserNumMapByLobby) WatchCallDelay(evt *clientv3.Event) {
	this.lock.Lock()
	defer this.lock.Unlock()
	groupid, _, sid := SplitLobbyUserKeyParam(string(evt.Kv.Key))
	_ = PATH_UserNum

	if evt.Type == mvccpb.PUT {
		//有人数信息更新
		val := common.NewString(string(evt.Kv.Value))
		var info = &UserNumValue{}
		json.Unmarshal(val.ToBytes(), info)
		if this.userNumMap[groupid] == nil {
			this.userNumMap[groupid] = make(map[uint64]*UserNumValue)
		}
		this.userNumMap[groupid][sid] = info
	} else if evt.Type == mvccpb.DELETE {
		//有人数信息删除,group为空时不处理
		delete(this.userNumMap[groupid], sid)
	}
}

// LoadWatchAll 加载监听所有服务器信息
func (this *UserNumMapByLobby) LoadWatchAll(key string) {
	this.lock.Lock()
	defer this.lock.Unlock()
	res, err := etcd.GetEtcd().GetPathAll(key)
	if err != nil {
		logger.Error("loadWatchAll:", err)
		return
	}
	for _, kv := range res.Kvs {
		groupid, _, sid := SplitLobbyUserKeyParam(string(kv.Key))
		_ = PATH_UserNum
		val := common.NewString(string(kv.Value))
		var info = &UserNumValue{}
		json.Unmarshal(val.ToBytes(), info)
		if this.userNumMap[groupid] == nil {
			this.userNumMap[groupid] = make(map[uint64]*UserNumValue)
		}
		this.userNumMap[groupid][sid] = info
	}
}

type IUserNumMap interface {
	GetUserNum(groupid uint32, serverId uint64) int
	GetUserNumByServerInfo(sinfo *iserver.ServerInfo) int
	GetAllUserNum() map[uint32]map[uint64]int
}

// 获得一个服务器的用户数量
func (this *UserNumMapByLobby) GetUserNum(groupid uint32, serverId uint64) int {
	this.lock.RLock()
	defer this.lock.RUnlock()
	if this.userNumMap[groupid] == nil {
		return 0
	}
	if this.userNumMap[groupid][serverId] == nil {
		return 0
	}
	return int(this.userNumMap[groupid][serverId].UserNum)
}

// 获得一个服务器的用户数量
func (this *UserNumMapByLobby) GetUserNumByServerInfo(sinfo *iserver.ServerInfo) int {
	return this.GetUserNum(sinfo.Group, sinfo.ServerID)
}

// 获得所有服务器的用户数量
func (this *UserNumMapByLobby) GetAllUserNum() map[uint32]map[uint64]*UserNumValue {
	this.lock.RLock()
	defer this.lock.RUnlock()
	copyMap := make(map[uint32]map[uint64]*UserNumValue)
	for groupId, gateNumMap := range this.userNumMap {
		copyv := make(map[uint64]*UserNumValue)
		for srvId, num := range gateNumMap {
			copyv[srvId] = &UserNumValue{}
			copyv[srvId].UserNum = num.UserNum
			copyv[srvId].RobotNum = num.RobotNum
		}
		copyMap[groupId] = copyv
	}
	return copyMap
}
